package DataStructure.array;

import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

/**
 * 448. 找到所有数组中消失的数字 https://leetcode.cn/problems/find-all-numbers-disappeared-in-an-array
 * 题目简述：一个含n个整数的数组nums中nums[i]在区间[1, n]内，找出所有在[1, n]范围内但没有出现在nums中的数字
 */
public class FindDisappearedNumbers {

    public static void main(String[] args) {
        new FindDisappearedNumbers().findDisappearedNumbers(new int[]{4,3,2,7,8,2,3,1});
    }

    /**
     * 思路一：通过编解码使一格可以存储两个信息。遍历数组，每遍历到一个值num，给num-1下标处的数值+n。
     * 完成后再遍历一次数组，所有<=n的元素下标+1即为消失的数字
     */
    public List<Integer> findDisappearedNumbers(int[] nums) {
        int n = nums.length;
        for (int num : nums) {
            //通过编解码使一格可以存储两个信息
            int x = (num - 1) % n;
            nums[x] += n;
        }
        List<Integer> ret = new ArrayList<Integer>();
        for (int i = 0; i < n; i++) {
            if (nums[i] <= n) {
                ret.add(i + 1);
            }
        }
        return ret;
    }

    public List<Integer> findDisappearedNumbers2(int[] nums) {
        for(int i = 0;i < nums.length;i++) {
            if (nums[i] !=0 && nums[i] != i+1) {
                int k = nums[i] - 1;
                nums[i] = 0;
                while(k != -1 && nums[k] != k+1) {
                    int t = nums[k] - 1;
                    nums[k] = k + 1;
                    k = t;
                }
            }
        }
        List<Integer> result = new ArrayList<>();
        for(int i = 0;i < nums.length;i++) {
            if(nums[i] == 0) {
                result.add(i + 1);
            }
        }
        return result;
    }

    /**
     * 思路：用一个HashSet存储数组中所有数值，然后再遍历1-n，查找不contains的元素
     */
    public List<Integer> findDisappearedNumbers3(int[] nums) {
        List<Integer> result = new ArrayList<>();
        Set<Integer> count = new HashSet<>();
        for (int num : nums) {
            count.add(num);
        }
        for (int i = 1; i <= nums.length; i++) {
            if (!count.contains(i)) {
                result.add(i);
            }
        }
        return result;
    }

}
